home *** CD-ROM | disk | FTP | other *** search
/ PCMania 73 / PCMania CD73_1.iso / sharewar / utiles / viff / viffutil.c < prev    next >
C/C++ Source or Header  |  1997-12-18  |  17KB  |  696 lines

  1. /************************* -*- Mode: C -*- *****************************
  2.  *
  3.  * viffutil.c -- utility functions for viff
  4.  *
  5.  * Copyright (C) 1996-1997 Richard Flamsholt S0rensen.  All rights reserved.
  6.  *
  7.  * Author          : Richard Flamsholt S0rensen
  8.  * Created On      : Wed Dec 18 16:00:06 1996
  9.  * Last Modified By: Richard Flamsholt S0rensen
  10.  * Last Modified On: Thu Dec 18 14:08:19 1997
  11.  * Update Count    : 43
  12.  * Revision History: None
  13.  *
  14.  * COMMENTS
  15.  * HISTORY
  16.  **********************************************************************/
  17.  
  18.  
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21.  
  22. #if   defined(SCO)
  23. # include <fcntl.h>
  24. # include <unistd.h>
  25. # include <dirent.h>
  26. #elif defined(BC31)
  27. # include <dir.h>
  28. #elif defined(MSVC)
  29. # include <direct.h>
  30. #elif defined(DJGPP)
  31. # include <dirent.h>
  32. #endif
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <ctype.h>
  37. #include <stdarg.h>
  38. #include <string.h>
  39. #include <errno.h>
  40. #include "viff.h"
  41.  
  42. #define WILD_MAXARGC    5000u
  43. #define WILD_MAXARGV    60000u
  44.  
  45. #ifndef S_ISDIR
  46. # ifndef S_IFDIR
  47. #  error Must be compiled with a compiler that has a decent stat() call
  48. # endif
  49. # define S_ISDIR(mode)    ((mode)&S_IFDIR)
  50. #endif
  51.  
  52. typedef struct {
  53.   int len;
  54.   char *skipext;
  55.   char *ifext;
  56. } GENERATED_FILE;
  57. static GENERATED_FILE generated_files[] = {
  58.   {2,".h",  ".asn"},            /* ASN.1 generated .h file */
  59.   {2,".c",  ".asn"},            /* ASN.1 generated .c file */
  60.   {2,".h",  ".y"},            /* yacc(1) generated .h file */
  61.   {2,".c",  ".y"},            /* yacc(1) generated .c file */
  62.   {2,".i",  ".c"},            /* preprocessed .c file */
  63.   {2,".elc",".el"},            /* compiled emacs-lisp file */
  64.   {0,NULL,NULL}
  65. };
  66.  
  67. typedef struct {
  68.   int len;
  69.   char *ext;
  70. } BINARY_EXT;
  71. static BINARY_EXT binary_ext[] = {
  72. #if defined(MSDOS) || defined(WIN32)
  73.   {4,".arj"},                /* ARJ archive */
  74.   {4,".bmp"},                /* bitmap */
  75.   {4,".com"},                /* DOS com-file */
  76.   {4,".dll"},                /* Windows DLL */
  77.   {4,".exe"},                /* DOS exe-file */
  78.   {4,".lib"},                /* library */
  79.   {4,".lzh"},                /* LHARC */
  80.   {4,".obj"},                /* object file */
  81.   {2,".z"  },                /* compressed file */
  82.   {4,".zip"},                /* PKZIP archive */
  83.   {4,".zoo"},                /* zoo archive */
  84.   {4,".aps"},                /* MSVC++ binary resource */
  85.   {4,".bsc"},                /* MSVC++ browser database */
  86.   {4,".clw"},                /* MSVC++ class wizard file */
  87.   {4,".mdp"},                /* MSVC++ project workspace file */
  88.   {4,".pdb"},                /* MSVC++ program database */
  89.   {4,".sbr"},                /* MSVC++ source browser file */
  90.   {4,".wsp"},                /* MSVC++ workspace information */
  91.   {4,".vcp"},                /* MSVC++ workspace information */
  92.   {4,".vcw"},                /* MSVC++ workbench status */
  93.   {4,".exp"},                /* MSVC++ export file */
  94.   {4,".res"},                /* MSVC++ compiled resource */
  95.   {4,".rct"},                /* MSVC++ resource template file */
  96. #endif
  97. #ifdef UNIX
  98.   {2,".Z"  },                /* Lempel-Ziv compressed file */
  99.   {2,".a"  },                /* statically linked library */
  100.   {3,".gz" },                /* GNU Zip */
  101.   {2,".o"  },                /* object file */
  102.   {4,".out"},                /* a.out */
  103.   {3,".so" },                /* dynamically linked library */
  104.   {4,".tar"},                /* tar archive */
  105.   {4,".uid"},                /* Motif resource file */
  106. #endif
  107.   {4,".gif"},
  108.   {0,NULL}
  109. };
  110.  
  111. static char *binary_files[] = {
  112. #ifdef UNIX
  113.   "a.out",
  114.   "core",
  115. #endif
  116.   NULL,
  117. };
  118.  
  119. static struct {
  120.   char **argv;
  121.   char *fnames;
  122. } constructed;
  123.  
  124.  
  125. static int vmessage(const char *fmt, va_list varg);
  126. static void free_constructed(void);
  127. static BOOLEAN find_diffcmd_do(char *path);
  128.  
  129.  
  130. void
  131. error(const char *fmt, ...)
  132. {
  133.   va_list varg;
  134.  
  135.   va_start(varg, fmt);
  136.   if (curses_on) {
  137.     (void)vmessage(fmt, varg);
  138.   } else {
  139.     fprintf(stderr, "viff: ");
  140.     vfprintf(stderr, fmt, varg);
  141.     fprintf(stderr, "\n");
  142.   }
  143.   va_end(varg);
  144.   exit(EXIT_FAILURE);
  145. }
  146.  
  147.  
  148. void
  149. panic(const char *fmt, ...)
  150. {
  151.   va_list varg;
  152.  
  153.   va_start(varg, fmt);
  154.   if (curses_on) {
  155.     (void)vmessage(fmt, varg);
  156.   } else {
  157.     fprintf(stderr, "Viff panic: ");
  158.     vfprintf(stderr, fmt, varg);
  159.     fprintf(stderr, "\n");
  160.   }
  161.   va_end(varg);
  162.   exit(EXIT_FAILURE);
  163. }
  164.  
  165.  
  166. void
  167. brief_usage(void)
  168. {
  169.   fprintf(stderr, "usage: viff files\n(use viff -h for help)\n");
  170.   exit(EXIT_FAILURE);
  171. }
  172.  
  173.  
  174. void
  175. extended_usage(void)
  176. {
  177.   printf("usage:\n"
  178.      "  viff  options  file file\n"
  179.      "  viff  options  files directory\n"
  180.      "  viff  options  directory files\n"
  181.      "  viff  options  directory directory\n"
  182.      "options:\n"
  183.      "  info:   -h            give this help\n"
  184.      "          -V            show viff version\n"
  185.      "  viff:   -v            verbose; report skipped files\n"
  186.      "          -lL           list differences; -L for brief\n"
  187.      "          -f filename   start viffing at this filename\n"
  188.      "  skip:   -i            ignore differences in headers\n"
  189.      "          -x            exclude generated files\n"
  190.      "  view:   -m            monocrome display\n"
  191.      "          -t width      set tabulator width\n"
  192.      "  diff:   -o option     pass option to diff\n"
  193.      "          -p program    use program instead of "DIFFCMD"\n"
  194.      "examples:\n"
  195.      "  viff *.c *.h makefile ../WORK\n"
  196.      "  viff -vlx *.* ../WORK\n"
  197.      "  viff -t 4 -o -b sved.c sved.bak\n");
  198.   exit(EXIT_SUCCESS);
  199. }
  200.  
  201.  
  202. int
  203. message(const char *fmt, ...)
  204. {
  205.   va_list varg;
  206.   int ch = 0;
  207.  
  208.   if (report) {
  209.     if (!brief_report) {
  210.       va_start(varg, fmt);
  211.       vprintf(fmt, varg);
  212.       va_end(varg);
  213.       putchar('\n');
  214.     }
  215.   } else {
  216.     va_start(varg, fmt);
  217.     ch = vmessage(fmt, varg);
  218.     va_end(varg);
  219.   }
  220.   return ch;
  221. }
  222.  
  223.  
  224. static int
  225. vmessage(const char *fmt, va_list varg)
  226. {
  227.   char buf[1000], *p=buf;
  228.   int ch, i, len, dx;
  229.  
  230.   *p++ = ' ';
  231.   p += vsprintf(p, fmt, varg);
  232.   p += sprintf(p, " (press a key)");
  233.   memset(p, ' ', COLS);
  234.   len = (int)(p-buf); dx = 0;
  235.   for (;;) {
  236.     attron(status_attr);
  237.     (void)move(VIEWLINES, 0);
  238.     (void)clrtoeol();
  239.     for (i = 0; i < COLS; i++) {
  240.       (void)addch(buf[dx+i]);
  241.     }
  242.     (void)standend();
  243.     (void)move(VIEWLINES, len-dx);
  244.     (void)refresh();
  245.     ch = getch();
  246.     switch (ch) {
  247.     case KEY_LEFT:
  248.     case KEYCTRL('B'): if (dx > 0) dx--; break;
  249.     case KEY_RIGHT:
  250.     case KEYCTRL('F'): if (dx+COLS < len) dx++; break;
  251.     case KEY_HOME:
  252.     case KEYCTRL('A'): dx = 0; break;
  253.     case KEY_END:
  254.     case KEYCTRL('E'): dx = MAX(0, len-COLS); break;
  255.     default:
  256.       (void)move(VIEWLINES, 0);
  257.       (void)clrtoeol();
  258.       (void)refresh();
  259.       if (ch == 'Q' && confirm_quit()) exit(EXIT_SUCCESS);
  260.       return ch;
  261.     }
  262.   }
  263. }
  264.  
  265.  
  266. BOOLEAN
  267. input(int flag, char *buf, const char *fmt, ...)
  268. {
  269.   va_list varg;
  270.   int inputpos;
  271.   int i, len, pos;
  272.   int ch;
  273.   char *p;
  274.  
  275.   va_start(varg, fmt);
  276.   inputpos = vstatusline(0, fmt, varg)+1;
  277.   va_end(varg);
  278.   pos = len = strlen(buf);
  279.  
  280.   (void)refresh();
  281.   for (;;) {
  282.     (void)move(VIEWLINES, inputpos);
  283.     (void)attron(status_attr);
  284.     for (i = 0; i < len; i++) {
  285.       (void)addch(buf[i]);
  286.     }
  287.     for (i = COLS-(inputpos+len); i-- > 0; ) {
  288.       (void)addch(' ');
  289.     }
  290.     (void)attroff(status_attr);
  291.     (void)move(VIEWLINES, inputpos+pos);
  292.     (void)refresh();
  293.     ch = getch();
  294.     if (KEYABORT(ch)) return FALSE;
  295.     if (KEYRETURN(ch)) break;
  296.     switch (ch) {
  297.     case KEY_LEFT:
  298.     case KEYCTRL('B'): if (pos > 0) pos--; break;
  299.     case KEY_RIGHT:
  300.     case KEYCTRL('F'): if (pos < len) pos++; break;
  301.     case KEY_HOME:
  302.     case KEYCTRL('A'): pos = 0; break;
  303.     case KEY_END:
  304.     case KEYCTRL('E'): pos = len; break;
  305.     case KEY_BACKSPACE:
  306.     case '\x08':
  307.       if (pos > 0) {
  308.     memmove(buf+pos-1, buf+pos, len-pos);
  309.     pos--; len--;
  310.       }
  311.       break;
  312.     case KEY_DELETE:
  313.     case KEY_DC:
  314.     case KEYCTRL('D'):
  315.       if (pos < len) {
  316.     memmove(buf+pos, buf+pos+1, len-pos-1);
  317.     len--;
  318.       }
  319.       break;
  320. #ifdef KEY_EOL
  321.     case KEY_EOL:
  322. #endif
  323.     case KEYCTRL('K'): len = pos; break;
  324.     default:
  325.       if ((flag & INPUT_NUMERIC) && !isdigit(ch)) break;
  326.       if (isspace(ch)) break;
  327.       if (inputpos+len < COLS-1 && PRINTABLE_CHAR(ch)) {
  328.     memmove(buf+pos+1, buf+pos, len-pos);
  329.     buf[pos] = (char)ch;
  330.     pos++; len++;
  331.       }
  332.     }
  333.   }
  334.   buf[len] = '\0';
  335.   while (isspace(*(unsigned char*)buf))
  336.     buf++;
  337.   for (p = buf+strlen(buf); p-- > buf; *p = '\0') {
  338.     if (!isspace(*(unsigned char*)p)) break;
  339.   }
  340.   if (buf[0] == '\0') return FALSE;
  341.   return TRUE;
  342. }
  343.  
  344.  
  345. int
  346. ask(char *text[], int nlines, char *accept, char escape, const char *fmt, ...)
  347. {
  348.   char buf[20];
  349.   va_list varg;
  350.   int xpos;
  351.  
  352.   va_start(varg, fmt);
  353.   xpos = vstatusline(STATUS_HELP, fmt, varg);
  354.   va_end(varg);
  355.   (void)move(VIEWLINES, xpos);
  356.  
  357.   xpos += sprintf(buf, " [%s]", accept)+1;
  358.   (void)attron(status_attr);
  359.   (void)addstr(buf);
  360.   (void)standend();
  361.  
  362.   (void)move(VIEWLINES, xpos);
  363.   (void)refresh();
  364.   for (;;) {
  365.     int ch = getch();
  366.     if (KEYABORT(ch)) return escape;
  367.     if (strchr(accept, tolower(ch))) return tolower(ch);
  368.     if (ch == KEY_F(1)) {
  369.       help(text, nlines);
  370.     } else {
  371.       (void)beep();
  372.     }
  373.   }
  374.   /*NOTREACHED*/
  375. }
  376.  
  377.  
  378. char *
  379. my_strerror(void)
  380. {
  381.   static char buf[100];
  382.   int len;
  383.  
  384.   strncpy(buf, strerror(errno), sizeof(buf)-1);
  385.   len = strlen(buf);
  386.   if (len > 0 && buf[len-1] == '\n') {
  387.     buf[len-1] = '\0';
  388.   }
  389.   return buf;
  390. }
  391.  
  392.  
  393. BOOLEAN
  394. is_dir(char *fname)
  395. {
  396.   struct stat st;
  397. #if defined(MSDOS) || defined(WIN32)
  398.   if (isalpha(((unsigned char*)fname)[0]) &&
  399.       fname[1] == ':' && fname[2] == '\0') return TRUE;
  400. #endif
  401.   return stat(fname, &st) == 0 && S_ISDIR(st.st_mode);
  402. }
  403.  
  404.  
  405. char *
  406. make_path(char *buf, char *fname)
  407. {
  408.   strcpy(buf, fname);
  409.   buf += strlen(buf);
  410.   if (buf[-1] != SEPCHAR                /* (fname is from argv[]; not empty) */
  411. #if defined(MSDOS) || defined(WIN32)
  412.       && buf[-1] != ':'                 /* don't turn eg "a:" into "a:\" */
  413. #endif
  414.       ) *buf++ = SEPCHAR;
  415.   return buf;
  416. }
  417.  
  418.  
  419. char *
  420. strip_path(char *fname)
  421. {
  422.   char *p;
  423.   for (p = fname+strlen(fname); fname < p; p--) {
  424.     if (p[-1]=='\\' || p[-1]==':' || p[-1]=='/') break;
  425.   }
  426.   return p;
  427. }
  428.  
  429.  
  430. char *
  431. lower_str(char *str)
  432. {
  433. #ifdef MSDOS
  434.   char *p;
  435.   for (p = str; *p; p++) {
  436.     *p = (char)tolower(*(unsigned char*)p);
  437.   }
  438. #endif
  439.   return str;
  440. }
  441.  
  442.  
  443. BOOLEAN
  444. find_diffcmd(void)
  445. {
  446.   char *path, *p;
  447.  
  448.   p = strip_path(diffcmd);
  449.   if (diffcmd < p) {            /* a path is given; check there */
  450.     return find_diffcmd_do("");
  451.   } else {
  452. #ifndef UNIX
  453.     if (find_diffcmd_do(".")) return TRUE;
  454. #endif
  455.     if ((path=getenv("PATH")) == NULL) return FALSE;
  456.     path = xstrdup(path);
  457.     for (p = strtok(path, PATHSEP); p; p = strtok(NULL, PATHSEP)) {
  458.       if (find_diffcmd_do(p)) break;
  459.     }
  460.     free(path);
  461.     return p ? TRUE : FALSE;
  462.   }
  463. }
  464.  
  465.  
  466. static BOOLEAN
  467. find_diffcmd_do(char *path)
  468. {
  469.   char buf[FILENAME_MAX+100], *p;        /* +n; don't push our luck... */
  470.   struct stat st;
  471.  
  472.   p = buf;
  473.   strcpy(p, path); p += strlen(p);
  474.   if (buf < p && p[-1] != SEPCHAR) *p++ = SEPCHAR;
  475.   strcpy(p, diffcmd);
  476. #if defined(MSDOS) || defined(WIN32)
  477.   { int len=strlen(p);
  478.     p += strlen(p);
  479.     if (len<4 || stricmp(p-4, ".exe")!=0) {
  480.       strcpy(p, ".exe");
  481.     }
  482.     if (stat(buf, &st) == 0) {
  483.       free(diffcmd); diffcmd = xstrdup(buf);
  484.       return TRUE;
  485.     }
  486.     if (len<4 || stricmp(p-4, ".com")!=0) {
  487.       strcpy(p, ".com");
  488.     }
  489.   }
  490. #endif
  491.   if (stat(buf, &st) == 0) {
  492.     free(diffcmd); diffcmd = xstrdup(buf);
  493.     return TRUE;
  494.   }
  495.   return FALSE;
  496. }
  497.  
  498.  
  499. void
  500. construct_argv(char *dir1, char *dir2, int *argcp, char ***argvp)
  501. {
  502.   int i, argc=0;
  503.   size_t fnamelen=0;
  504.   char **argv=xmalloc((WILD_MAXARGC+1)*sizeof(char**));
  505.   char *fnames=xmalloc(WILD_MAXARGV+FILENAME_MAX+1);
  506.   char *fname;
  507. #ifdef BC31
  508.   struct ffblk ffblk;
  509.   char dirbuf[FILENAME_MAX+50];
  510.   int res;
  511.   strcpy(make_path(dirbuf, dir1), "*.*");
  512.   for (res = findfirst(dirbuf, &ffblk, 0); res==0; res = findnext(&ffblk)) {
  513.     fname = ffblk.ff_name;
  514. #elif defined(MSVC)
  515.   struct _find_t findt;
  516.   char dirbuf[FILENAME_MAX+50];
  517.   unsigned res;
  518.   strcpy(make_path(dirbuf, dir1), "*.*");
  519.   for (res = _dos_findfirst(dirbuf, _A_RDONLY|_A_SYSTEM, &findt);
  520.        res == 0; res = _dos_findnext(&findt)) {
  521.     fname = findt.name;
  522. #else
  523.   DIR *dirp;
  524.   struct dirent *dirent;
  525.   dirp = opendir(dir1);
  526.   if (dirp == NULL) error("cannot read directory '%s'", dir1);
  527.   while ((dirent=readdir(dirp)) != NULL) {
  528.     fname = dirent->d_name;
  529. #endif
  530.     if (strcmp(fname, ".")==0 || strcmp(fname, "..")==0) continue;
  531.     if (argc == WILD_MAXARGC) {
  532.       error("more than %d files in %s", argc, dir1);
  533.     }
  534.     if (fnamelen >= WILD_MAXARGV-(FILENAME_MAX+1)) {
  535.       error("total filename lengths in %s exceeds %lu bytes",
  536.         dir1, (long unsigned)fnamelen);
  537.     }
  538.     strcpy(make_path(fnames+fnamelen, dir1), fname);
  539.     argv[argc++] = (char*)fnamelen;    /* an offset; adjust later */
  540.     fnamelen += strlen(fnames+fnamelen)+1;
  541.   }
  542.  
  543.   /* as the last member of argv[], add the directory to viff against */
  544.   argv[argc++] = (char*)fnamelen;    /* an offset; adjust later */
  545.   strcpy(fnames+fnamelen, dir2);
  546.   fnamelen += strlen(dir2)+1;
  547.  
  548.   /* now compact the two tables (argc,fnamelen are both >0 because of dir2) */
  549.   constructed.argv = argv = xrealloc(argv, argc * sizeof(char**));
  550.   constructed.fnames = fnames = xrealloc(fnames, fnamelen);
  551.   for (i = 0; i < argc; i++) {        /* realloc(fnames) done; adjust now */
  552.     argv[i] = fnames + (size_t)(long)argv[i];
  553.   }
  554.  
  555.   *argcp = argc;
  556.   *argvp = constructed.argv;
  557.   atexit(free_constructed);
  558. }
  559.  
  560.  
  561. static void
  562. free_constructed(void)
  563. {
  564.   free(constructed.argv);
  565.   free(constructed.fnames);
  566. }
  567.  
  568.  
  569. void
  570. skip_directories(int from, int to, char *argv[])
  571. {
  572.   int i;
  573.  
  574.   for (i = from; i < to; i++) {
  575.     if (argv[i] == NULL) continue;
  576.     if (is_dir(argv[i])) {
  577.       argv[i] = NULL;
  578.     }
  579.   }
  580. }
  581.  
  582.  
  583. void
  584. skip_generated_files(int from, int to, char *argv[])
  585. {
  586.   GENERATED_FILE *g;
  587.   char fnamebuf[FILENAME_MAX];
  588.   char *fname;
  589.   int len;
  590.   int skipped;
  591.   int i, j;
  592.  
  593.   /* compare fname's extension with those in g->skipext
  594.      if found then
  595.        put "fname.ifext" into fnamebuf
  596.        look through all non-processes files again and compare it to fnamebuf
  597.        if found then
  598.          this means that the file being tested should be skipped
  599.    */
  600.   skipped = 0;
  601.   for (i = from; i < to; i++) {
  602.     if (argv[i] == NULL) continue;
  603.     fname = argv[i];
  604.     len = strlen(fname);
  605.     for (g = generated_files; g->skipext; g++) {
  606.       if (g->len <= len && strcmp(fname+len-g->len, g->skipext)==0) {
  607.     strcpy(fnamebuf, strip_path(fname));
  608.     strcpy(strchr(fnamebuf, '.'), g->ifext);  /* we know there's a . */
  609.     for (j = from; j < to; j++) {
  610.       if (argv[j] == NULL) continue;
  611.       if (strcmp(fnamebuf, strip_path(argv[j])) == 0) {
  612.         if (verbose) message("skipping generated file %s",fname);
  613.         argv[i] = NULL;
  614.         skipped++;
  615.         break;
  616.       }
  617.     }
  618.     break;
  619.       }
  620.     }
  621.   }
  622.   if (!verbose && skipped>0) {
  623.     message("skipping %d generated file%s", skipped, skipped==1 ? "" : "s");
  624.   }
  625. }
  626.  
  627.  
  628. void
  629. skip_binary_files(int from, int to, char *argv[])
  630. {
  631.   BINARY_EXT *be;
  632.   char **b;
  633.   int i, len, skipped;
  634.  
  635.   skipped = 0;
  636.   for (i = from; i < to; i++) {
  637.     if (argv[i] == NULL) continue;
  638.     for (b = binary_files; *b; b++) {
  639.       if (strcmp(*b, argv[i]) == 0) {
  640.     if (verbose) message("skipping binary file %s", argv[i]);
  641.     argv[i] = NULL;
  642.     skipped++;
  643.     break;
  644.       }
  645.     }
  646.     if (argv[i] == NULL) continue;
  647.     len = strlen(argv[i]);
  648.     for (be = binary_ext; be->len > 0; be++) {
  649.       if (be->len <= len && strcmp(argv[i]+len-be->len, be->ext)==0) {
  650.     if (verbose) message("skipping binary file %s", argv[i]);
  651.     argv[i] = NULL;
  652.     skipped++;
  653.     break;
  654.       }
  655.     }
  656.   }
  657.   if (!verbose && skipped > 0) {
  658.     message("skipping %d binary file%s", skipped, skipped==1 ? "" : "s");
  659.   }
  660. }
  661.  
  662.  
  663. #ifdef MALLORY_FLAG
  664. #undef xmalloc
  665. #undef xrealloc
  666. #undef xstrdup
  667. #endif
  668.  
  669. void *
  670. xmalloc(size_t size)
  671. {
  672.   void *ptr = malloc(size==0 ? 1 : size);  /* turn malloc(0) into malloc(1) */
  673.   if (ptr == NULL) {
  674.     panic("malloc(%lu) failed", (long unsigned)size);
  675.   }
  676.   return ptr;
  677. }
  678.  
  679. void *
  680. xrealloc(void *ptr, size_t size)
  681. {
  682.   void *newptr = realloc(ptr, size);
  683.   if (newptr == NULL) {
  684.     panic("realloc(p,%lu) failed", (long unsigned)size);
  685.   }
  686.   return newptr;
  687. }
  688.  
  689. char *
  690. xstrdup(char *str)
  691. {
  692.   return strcpy(xmalloc(strlen(str)+1), str);
  693. }
  694.  
  695.  
  696.